package com.gitee.hljdrl.utils.date;

import android.os.Parcel;
import android.os.Parcelable;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.Calendar;
import java.util.Date;

public class CalendarDay implements Parcelable {
    private final int year;
    private final int month;
    private final int day;
    private transient Calendar _calendar;
    private transient Date _date;
    public static final Creator<CalendarDay> CREATOR = new Creator<CalendarDay>() {
        public CalendarDay createFromParcel(Parcel in) {
            return new CalendarDay(in);
        }

        public CalendarDay[] newArray(int size) {
            return new CalendarDay[size];
        }
    };

    @NonNull
    public static CalendarDay today() {
        return from(CalendarUtils.getInstance());
    }

    @NonNull
    public static CalendarDay from(int year, int month, int day) {
        return new CalendarDay(year, month, day);
    }

    public static CalendarDay from(@Nullable Calendar calendar) {
        return calendar == null ? null : from(CalendarUtils.getYear(calendar), CalendarUtils.getMonth(calendar), CalendarUtils.getDay(calendar));
    }

    public static CalendarDay from(@Nullable Date date) {
        return date == null ? null : from(CalendarUtils.getInstance(date));
    }

    /** @deprecated */
    @Deprecated
    public CalendarDay() {
        this(CalendarUtils.getInstance());
    }

    /** @deprecated */
    @Deprecated
    public CalendarDay(Calendar calendar) {
        this(CalendarUtils.getYear(calendar), CalendarUtils.getMonth(calendar), CalendarUtils.getDay(calendar));
    }

    /** @deprecated */
    @Deprecated
    public CalendarDay(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    /** @deprecated */
    @Deprecated
    public CalendarDay(Date date) {
        this(CalendarUtils.getInstance(date));
    }

    public int getYear() {
        return this.year;
    }

    public int getMonth() {
        return this.month;
    }

    public int getDay() {
        return this.day;
    }

    @NonNull
    public Date getDate() {
        if (this._date == null) {
            this._date = this.getCalendar().getTime();
        }

        return this._date;
    }

    @NonNull
    public Calendar getCalendar() {
        if (this._calendar == null) {
            this._calendar = CalendarUtils.getInstance();
            this.copyTo(this._calendar);
        }

        return this._calendar;
    }

    void copyToMonthOnly(@NonNull Calendar calendar) {
        calendar.clear();
        calendar.set(this.year, this.month, 1);
    }

    public void copyTo(@NonNull Calendar calendar) {
        calendar.clear();
        calendar.set(this.year, this.month, this.day);
    }

    public boolean isInRange(@Nullable CalendarDay minDate, @Nullable CalendarDay maxDate) {
        return (minDate == null || !minDate.isAfter(this)) && (maxDate == null || !maxDate.isBefore(this));
    }

    public boolean isBefore(@NonNull CalendarDay other) {
        if (other == null) {
            throw new IllegalArgumentException("other cannot be null");
        } else if (this.year == other.year) {
            return this.month == other.month ? this.day < other.day : this.month < other.month;
        } else {
            return this.year < other.year;
        }
    }

    public boolean isAfter(@NonNull CalendarDay other) {
        if (other == null) {
            throw new IllegalArgumentException("other cannot be null");
        } else if (this.year == other.year) {
            return this.month == other.month ? this.day > other.day : this.month > other.month;
        } else {
            return this.year > other.year;
        }
    }

    public boolean equals(Object o) {
        if (this == o) {
            return true;
        } else if (o != null && this.getClass() == o.getClass()) {
            CalendarDay that = (CalendarDay)o;
            return this.day == that.day && this.month == that.month && this.year == that.year;
        } else {
            return false;
        }
    }

    public int hashCode() {
        return hashCode(this.year, this.month, this.day);
    }

    private static int hashCode(int year, int month, int day) {
        return year * 10000 + month * 100 + day;
    }

    public String toString() {
        return "CalendarDay{" + this.year + "-" + this.month + "-" + this.day + "}";
    }

    public CalendarDay(Parcel in) {
        this(in.readInt(), in.readInt(), in.readInt());
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.year);
        dest.writeInt(this.month);
        dest.writeInt(this.day);
    }
}
